package com.airlines.crewassignment.domain.util;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.joda.time.DateTime;

import com.airlines.common.DateTimeRangeUtil;
import com.airlines.common.SpringContextUtil;
import com.airlines.crewassignment.constant.CrewTaskConstant;
import com.airlines.crewassignment.constant.RuleConstant;
import com.airlines.crewassignment.domain.Crew;
import com.airlines.crewassignment.domain.CrewLinkLineRosterGlobalValue;
import com.airlines.crewassignment.domain.CrewPositionAssignment;
import com.airlines.crewassignment.domain.CrewTask;
import com.airlines.crewassignment.domain.DateTimeRange;
import com.airlines.crewassignment.domain.LinkLine;
import com.airlines.crewassignment.domain.crew.CrewRestDateTime;
import com.airlines.crewassignment.service.crew.CrewRestDateTimeService;

/**
 * @author xxxx
 * @date 2018年5月3日 
 * @description 机组人员休息期计算工具类
 */
public class CrewRestUtil {
	private static CrewRestDateTimeService crewRestDateTimeService;
	private static CrewRestDateTimeService getCrewRestDateTimeService(){
		if(crewRestDateTimeService == null){
			crewRestDateTimeService = (CrewRestDateTimeService)SpringContextUtil.getBean(CrewRestDateTimeService.class);
		}
		return crewRestDateTimeService;
	}
	
	/**
	 * 执行飞行任务前144小时，应至少包含连续48+X小时休息期
	 * 当前任务连线的首航班起飞时间减144小时的范围内，存在连续48小时+X小时（来回路程）未安排任务的记录，且没有任何除因私加机组外的其他不在位信息。
	 * @param list
	 * @param crew
	 * @return
	 */
	public static boolean has48xRestBefore144(List<CrewPositionAssignment> list,Crew crew,CrewLinkLineRosterGlobalValue crewLinkLineRosterGlobalValue){
		//1.计算当前排班期间的休息期
		DateTimeRange superRestInWorkSpace = crewLinkLineRosterGlobalValue.getAssignmentDateRange();
		//2.查询计算包含排班前以及工作空间内的所有休息期
		List<CrewRestDateTime> restListAll = getCrewRestDateTimeAll(list, crew, superRestInWorkSpace);
		//3.获取每个连线的开始时间，以及往前推144小时
		for(CrewPositionAssignment cpa : list){
			LinkLine linkLine = cpa.getPosition().getLinkLine();
			DateTime end = new DateTime(linkLine.getTd());
			DateTime start = end.minusHours(RuleConstant.REST_FLIGHT_BEFORE_144);
			DateTimeRange linkLineBeforeRange = new DateTimeRange(start,end);
			int count = getLowestRestCount(restListAll,crew,linkLineBeforeRange,RuleConstant.REST_48+RuleConstant.REST_X);
			if(count == 0){
				return false;	
			}		
		}
		
		return true;
	}
	
	/**
	 * 当前任务连线的首航班起飞时间减10+2小时范围内，没有排班记录或模拟机、本场的记录以及其他任务安排如置位、备份等。。
	 * @param list
	 * @param crew
	 * @param crewLinkLineRosterGlobalValue
	 * @return
	 */
	public static boolean has10xRestBefore(List<CrewPositionAssignment> list,Crew crew,CrewLinkLineRosterGlobalValue crewLinkLineRosterGlobalValue){
		//1.计算当前排班期间的休息期
		DateTimeRange superRestInWorkSpace = crewLinkLineRosterGlobalValue.getAssignmentDateRange();
		//2.查询计算包含排班前以及工作空间内的所有休息期
		List<CrewRestDateTime> restListAll = getCrewRestDateTimeAll(list, crew, superRestInWorkSpace);
		//3.获取每个连线的开始时间，以及往前推10+X小时
		for(CrewPositionAssignment cpa : list){
			LinkLine linkLine = cpa.getPosition().getLinkLine();
			DateTime end = new DateTime(linkLine.getTd());
			DateTime start = end.minusHours(RuleConstant.REST_FLIGHT_BEFORE_10+RuleConstant.REST_X);
			DateTimeRange linkLineBeforeRange = new DateTimeRange(start,end);
			int count = getLowestRestCount(restListAll,crew,linkLineBeforeRange,RuleConstant.REST_FLIGHT_BEFORE_10+RuleConstant.REST_X);
			if(count == 0){
				return false;	
			}		
		}
		return true;
	}
	
	/**
	 * 从空间内，空间外所有的休息期中，按照某段时间段，获取最少为lowestRest的休息期的个数
	 * @param restListAll
	 * @param dateTimeRange
	 * @param lowestRest
	 * @return
	 */
	public static int getLowestRestCount(List<CrewRestDateTime> restListAll,Crew crew,DateTimeRange dateTimeRange,int lowestRest){
		//0.增强判断，如果没有休息期，则必定返回0
		if(CollectionUtils.isEmpty(restListAll)){
			return 0;
		}
		
		//1.将dateTimeRange 也视为一个休息期
		CrewRestDateTime crdt = new CrewRestDateTime();
		crdt.setWorkcode(crew.getWorkcode());
		crdt.setRestDateTimeRange(dateTimeRange);
		
		//2.加入总休息期
		restListAll.add(crdt);
		
		//3.重新计算休息期
		CrewRestDateTimeService crewRestDateTimeService = getCrewRestDateTimeService();
		List<CrewRestDateTime> listHander = crewRestDateTimeService.listCrewRestDateTime(crew.getWorkcode(), listDateTimeRange(restListAll));
		
		int lowestRestCount = 0;
		
		for(CrewRestDateTime crewRestDateTime : listHander){
			DateTimeRange dtr = crewRestDateTime.getRestDateTimeRange();
			//经过以上计算后，如果休息期与要求的时间范围没有交集，则不属于此时间范围内的休息期，不做计算
			if(!DateTimeRangeUtil.isIntersection(dateTimeRange,dtr)){
				continue;
			
			}
			int restDuration = dtr.getDuration();
			if(restDuration>=lowestRest*60){
				lowestRestCount++ ;
			}
		}
		
		return lowestRestCount;
	}
	
	/**
	 * 查询计算包含排班前以及工作空间内的所有休息期
	 * @param list
	 * @param crew
	 * @param superRestInWorkSpace
	 * @return
	 */
	private static List<CrewRestDateTime> getCrewRestDateTimeAll(List<CrewPositionAssignment> list,Crew crew,	DateTimeRange superRestInWorkSpace){		
		List<CrewTask> crewTaskInWorkSpace = crewTaskBuild(list, crew);
		CrewRestDateTimeService crewRestDateTimeService = getCrewRestDateTimeService();
		
		//获取工作空间内的休息期
		List<CrewRestDateTime> restListInWorkSpace = crewRestDateTimeService.listCrewRestDateTime(crew.getWorkcode(), crewTaskInWorkSpace, superRestInWorkSpace);
		//获取排班前的休息期
		List<CrewRestDateTime> restListBeforeFlight = crew.getCrewFlightExperience().getCrewRestDateTimeList();
		
		List<DateTimeRange> restListAllInit = new ArrayList<>();
		restListAllInit.addAll(listDateTimeRange(restListInWorkSpace));
		restListAllInit.addAll(listDateTimeRange(restListBeforeFlight));
		
		//获取合并整理后的该飞行员的所有休息期
		List<CrewRestDateTime> restListAll = crewRestDateTimeService.listCrewRestDateTime(crew.getWorkcode(), restListAllInit);
		
		return restListAll;
	}
	
	/**
	 * 将空间中连线转换为机组任务
	 * @param list
	 * @param crew
	 * @return
	 */
	private static List<CrewTask> crewTaskBuild(List<CrewPositionAssignment> list,Crew crew){
		List<CrewTask> crewTaskList = new ArrayList<>();
		for(CrewPositionAssignment cpa : list){
			LinkLine linkLine = cpa.getPosition().getLinkLine();
			
			CrewTask crewTask = new CrewTask();
			crewTask.setWorkcode(crew.getWorkcode());
			crewTask.setStart(linkLine.getTd());
			crewTask.setEnd(linkLine.getTa());
			crewTask.setDateTimeRange(new DateTimeRange(linkLine.getTd(),linkLine.getTa()));
			crewTask.setTaskType(CrewTaskConstant.TASK_TYPE_FLIGHT);
			crewTask.setTaskName(CrewTaskConstant.TASK_TYPE_FLIGHT_NAME);
			crewTask.setTaskDesc(linkLine.getFlightCom() + linkLine.getFlightVoyage());
			
			crewTaskList.add(crewTask);
		}
		
		return crewTaskList;
	}
	
	/**
	 * 将休息期转换为时间片段list
	 * @param list
	 * @return
	 */
	public static List<DateTimeRange> listDateTimeRange(List<CrewRestDateTime> list){
		List<DateTimeRange> dateTimeRangeList = new ArrayList<>();
		for(CrewRestDateTime crdt : list){
			dateTimeRangeList.add(crdt.getRestDateTimeRange());
		}
		
		return dateTimeRangeList;
	}
}
